package com.yunji.framework_template.biz.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.http.client.ClientProtocolException;
import org.jsoup.nodes.Element;
import org.jsoup.parser.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import com.yunji.framework_template.biz.cache.EhDataCache;
import com.yunji.framework_template.biz.vo.appannie.AppAnnieVO;
import com.yunji.framework_template.biz.vo.appannie.Detail;
import com.yunji.framework_template.common.http.HttpConnection;
import com.yunji.framework_template.common.util.FileUtil;
import com.yunji.framework_template.common.util.StringUtil;
import com.yunji.framework_template.common.web.HttpResult;
import com.yunji.framework_template.common.web.Page;
import com.yunji.framework_template.orm.persistence.mapper.AppsMapper;
import com.yunji.framework_template.orm.persistence.model.Apps;
import lombok.extern.slf4j.Slf4j;

/**
 * Created by fenglibin on 2018/12/12.
 */
@Slf4j
@Service
public class AppsService {

    @Autowired
    private AppsMapper      appsMapper;

    @Value("#{settings['appAnnieGooglePlayAppsRankingFile']}")
    private String          appAnnieGooglePlayAppsRankingFile;
    @Resource
    private AppannieService appannieService;
    @Resource
    protected EhDataCache   ehDataCache;

    public int deleteByPrimaryKey(String packageName) {
        return appsMapper.deleteByPrimaryKey(packageName);
    }

    public int insert(Apps record) {
        return appsMapper.insert(record);
    }

    public int insertSelective(Apps record) {
        return appsMapper.insertSelective(record);
    }

    public Apps selectByPrimaryKey(String packageName) {
        Apps apps = ehDataCache.get("apps-" + packageName, Apps.class);
        if (apps != null) {
            return apps;
        }
        apps = appsMapper.selectByPrimaryKey(packageName);
        if (apps != null) {
            ehDataCache.put("apps-" + apps.getPackageName(), apps);
        }
        return apps;
    }

    public int updateByPrimaryKeySelective(Apps record) {
        return appsMapper.updateByPrimaryKeySelective(record);
    }

    public int updateByPrimaryKey(Apps record) {
        return appsMapper.updateByPrimaryKey(record);
    }

    /**
     * 将今天没有更新的App的排名降低
     * 
     * @return
     */
    public int updateSeq() {
        return appsMapper.updateSeq();
    }

    public List<Apps> selectByCondition(Apps record) {
        return appsMapper.selectByCondition(record);
    }

    public List<Apps> selectAll() {
        return appsMapper.selectAll();
    }

    public List<Apps> selectByPage(Page<Apps> page) {
        return appsMapper.selectByPage(page);
    }

    /**
     * 根据seq的升序做分页查询
     * 
     * @param page
     * @return
     */
    public List<Apps> selectByPageOrderBySeq(Page<Apps> page) {
        return appsMapper.selectByPageOrderBySeq(page);
    }

    public Integer count(Apps record) {
        return appsMapper.count(record);
    }

    public int deleteByCondition(Apps record) {
        return appsMapper.deleteByCondition(record);
    }

    public int deleteIconIsNull() {
        return appsMapper.deleteIconIsNull();
    }

    /**
     * 加载指定国家的google play应用排行数据
     * 
     * @param countryCode
     * @param filePath
     * @throws IOException
     */
    public void loadAppsFromFile(String countryCode, String filePath) throws IOException {
        loadAppsFromFile(filePath);
    }

    /**
     * 从默认的文件中读取应用的数据
     * 
     * @param filePath
     * @throws IOException
     */
    public void loadAppsFromFile() throws IOException {
        loadAppsFromFile(null);
    }

    /**
     * 从文件中读取应用的数据
     * 
     * @param filePath
     * @throws IOException
     */
    public void loadAppsFromFile(String filePath) throws IOException {
        if (filePath == null) {
            filePath = appAnnieGooglePlayAppsRankingFile;
        }
        log.info("Begin to load apps data from file:" + filePath);
        String appStr = FileUtil.read(filePath);
        loadApps(appStr);
    }

    /**
     * 从AppAnnie加载指定国家的应用数据
     * 
     * @param countryCode
     * @throws ClientProtocolException
     * @throws IOException
     */
    public void loadAppsFromAppAnnie(String countryCode) throws ClientProtocolException, IOException {
        loadApps(appannieService.getData(countryCode));
    }

    /**
     * 从AppAnnie的Json格式加载到数据库中
     * 
     * @throws IOException
     */
    public void loadApps(String appAnnieJsonStr) throws IOException {

        if (StringUtil.isEmpty(appAnnieJsonStr)) {
            return;
        }

        List<Apps> allApps = new ArrayList<Apps>();
        List<Apps> list1 = new ArrayList<Apps>();
        List<Apps> list2 = new ArrayList<Apps>();
        List<Apps> list3 = new ArrayList<Apps>();
        List<Apps> list4 = new ArrayList<Apps>();
        List<Apps> list5 = new ArrayList<Apps>();
        Map<Integer, List<Apps>> appListMap = new HashMap<Integer, List<Apps>>();
        Set<String> packageNameSet = new HashSet<String>();
        appListMap.put(0, list1);
        appListMap.put(1, list2);
        appListMap.put(2, list3);
        appListMap.put(3, list4);
        appListMap.put(4, list5);
        AppAnnieVO appAnnieVO = JSONObject.parseObject(appAnnieJsonStr, AppAnnieVO.class);
        List<List<?>> rows = appAnnieVO.getTable().getRows();
        for (List<?> row : rows) {
            // 取得名次
            int seq = Integer.parseInt(String.valueOf(row.get(0)));
            // 第一个值是名次，去掉
            row.remove(0);
            @SuppressWarnings("rawtypes")
            List<List> appsList = JSONObject.parseArray(JSON.toJSONString(row), List.class);
            int index = 0;
            for (List<?> detailLists : appsList) {
                List<Detail> detailList = JSONObject.parseArray(JSON.toJSONString(detailLists), Detail.class);
                Detail detail = detailList.get(0);

                if (detail.getName() == null || detail.getName().indexOf("*****") >= 0) {// 不可用的信息
                    continue;
                }

                String packageName = detail.getUrl().split("/")[4];
                if (packageNameSet.contains(packageName)) {
                    continue;
                }
                packageNameSet.add(packageName);
                Apps app = new Apps();
                app.setName(detail.getName());
                app.setPackageName(packageName);
                app.setCompanyName(detail.getCompany_name());
                app.setCountryCode(detail.getCountry_code());
                app.setHeaderquarters(detail.getHeaderquarters());
                app.setSeq(seq);
                appListMap.get(index).add(app);
                index++;
            }
        }
        /**
         * 以下逻辑是排序逻辑，每种分类分别取前面50个做交叉性排序
         */
        int num = 50;
        int seq = 0;
        for (int batch = 0; batch < 10; batch++) {
            int startIndex = (batch * num);
            for (int typeId = 0; typeId < 5; typeId++) {
                List<Apps> list = appListMap.get(typeId);
                for (int index = 0; index < 50; index++) {
                    if ((startIndex + index) >= list.size()) {
                        break;
                    }
                    seq++;
                    Apps app = list.get(startIndex + index);
                    app.setSeq(seq);
                    allApps.add(app);
                }
            }
        }
        /**
         * 插入或者更新排名
         */
        for (Apps app : allApps) {
            Apps existsApp = selectByPrimaryKey(app.getPackageName());
            if (existsApp != null) {
                existsApp.setSeq(app.getSeq());
                existsApp.setAdded(new Date());
                updateByPrimaryKey(existsApp);
            } else {
                insert(app);
            }
        }
        /**
         * 把本次没有更新的App的排名往后调整，因为其不在本次的名单中，说明其排序有下降
         */
        updateSeq();
        log.info("Finished load apps data from file");
    }

    /**
     * 从Google play获取应用的icon
     */
    public void getAppIconFromGooglePlay() {
        log.info("Begin to get app icon from google play.");
        String url = "https://play.google.com/store/apps/details?id=";
        int pageSize = 100;
        int currentPage = 1;
        int totalCount = appsMapper.countIconIsNull(new Apps());
        while (true) {
            Page<Apps> page = new Page<Apps>(currentPage, pageSize);
            page = page.reverseDisplayCalculate(totalCount);
            List<Apps> list = appsMapper.selectIconIsNull(page);
            if (list != null) {
                list.forEach(app -> {
                    log.info(app.getPackageName());
                    if (!StringUtil.isEmpty(app.getIcon())) {
                        return;
                    }
                    String appUrl = url + app.getPackageName();
                    try {
                        HttpResult result = HttpConnection.doGet(appUrl);
                        if (result.getCode() == 200) {
                            Element contentElement = new Element(Tag.valueOf("contents"), appUrl);
                            contentElement.html(result.getContent());
                            Element iconElement = contentElement.select("div[class=\"dQrBL\"]>img").first();
                            String iconUrl = iconElement.absUrl("src");
                            if (!StringUtil.isEmpty(iconUrl) && iconUrl.startsWith("http")) {
                                Apps updateApp = new Apps();
                                updateApp.setPackageName(app.getPackageName());
                                updateApp.setIcon(iconUrl);
                                updateByPrimaryKeySelective(updateApp);
                            }

                        }
                    } catch (Exception e) {
                        log.error("Get icon exception happened:" + appUrl, e);
                    }

                });
            }
            if (list == null || list.size() < pageSize) {
                break;
            }
            currentPage++;
        }
        log.info("Finish get app icon from google play.");
    }

    public int addViewsByPrimaryKey(Apps record) {
        int result = appsMapper.addViewsByPrimaryKey(record);
        if (result > 0) {
            record.setViews(record.getViews() == null ? 1 : record.getViews() + 1);
            ehDataCache.put("apps-" + record.getPackageName(), record);
        }
        return result;
    }
}
